package com.chenyaowei.happyhub.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.chenyaowei.happyhub.excepiton.BasicException;
import com.chenyaowei.happyhub.excepiton.ExceptionEnum;
import com.chenyaowei.happyhub.excepiton.ParamException;
import com.chenyaowei.happyhub.pojo.wechatuser.WxLoginResultDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 用于用户认证的filter
 *
 * @author tanwubo
 */
@Slf4j
public class WxAppletAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    @Value("${wx.appid}")
    private String appid;

    @Value("${wx.appsecret}")
    private String appsrcret;

    private String wxAuthUrl = "https://api.weixin.qq.com/sns/jscode2session?appid={appid}&secret={secret}&js_code={code}&grant_type=authorization_code";

    public WxAppletAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {
        String code = httpServletRequest.getParameter("code");
        if (StringUtils.isBlank(code)) {
            log.error("code is null");
            throw new ParamException(ExceptionEnum.PARAM_EXCEPTION.customMessage("code is null"));
        }
        String rawData = httpServletRequest.getParameter("rawData");
        if (StringUtils.isBlank(rawData)) {
            log.error("rawData is null");
            throw new ParamException(ExceptionEnum.PARAM_EXCEPTION.customMessage("rawData is null"));
        }
        String signature = httpServletRequest.getParameter("signature");
        if (StringUtils.isBlank(signature)) {
            log.error("signature is null");
            throw new ParamException(ExceptionEnum.PARAM_EXCEPTION.customMessage("signature is null"));
        }
        UriComponents uriComponents = UriComponentsBuilder
                .fromUriString(wxAuthUrl)
                .encode()
                .build();
        String url = uriComponents.expand(appid, appsrcret, code).toUriString();
        log.debug("wx auth url: [{}]", url);
        WebClient webClient = WebClient.create();
        Mono<String> mono = webClient.get().uri(url).accept(MediaType.TEXT_PLAIN).retrieve().bodyToMono(String.class);
        //= restTemplate.getForObject(url, WxLoginResultDTO.class);
        String object = mono.block();
        ObjectMapper mapper = new ObjectMapper();
        WxLoginResultDTO wxLoginResult = mapper.readValue(object,WxLoginResultDTO.class);
        if (wxLoginResult.getErrcode() != null && !wxLoginResult.getErrcode().equals(0)) {
            log.error("wx auth failed, errCode is [{}], errMsg is [{}]", wxLoginResult.getErrcode(), wxLoginResult.getErrmsg());
            throw new BasicException(ExceptionEnum.WX_AUTH_FAILED.customMessage("wx auth failed, errCode is [%s], errMsg is [%s]", wxLoginResult.getErrcode(), wxLoginResult.getErrmsg()));
        }
        log.info("string result: [{}]", object);
        log.info("wx login result: [{}]", wxLoginResult);
        return this.getAuthenticationManager().authenticate(new WxAppletAuthenticationToken(wxLoginResult.getOpenid(), wxLoginResult.getSession_key(), rawData, signature));
    }

}